package network;

import com.sghd.common.utils.ManagedException;
import com.sghd.common.utils.json.JsonUtils;
import game.dic.TishiManager;
import game.model.ConneReq;
import game.service.GameService;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.AttributeKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import utils.encrypt.DecryptUtil;

import java.util.Map;

/**
 * @author fank
 * @date 2018/03/06
 */
@Component
@ChannelHandler.Sharable
public class ServerHandler extends ChannelInboundHandlerAdapter {
    public static Logger logger = LoggerFactory.getLogger(ServerHandler.class);
    public static AttributeKey<Long> PLAYER_KEY = AttributeKey.valueOf("playerId");
    @Autowired
    private GameService gameService;

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            if (event.state() == IdleState.READER_IDLE) {
                logger.debug("超时未收到客户端消息,服务器主动关闭连接！");
                ctx.close();
            }
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (logger.isDebugEnabled()) {
            String id = ctx.channel().id().toString();
            if (ctx.channel().attr(PLAYER_KEY).get() != null) {
                id = ctx.channel().attr(PLAYER_KEY).get().toString();
            }
            logger.debug(id + "<---来自客户端:{}", msg.toString());
        }
        String[] strs = msg.toString().split(NetServer.MSG_SPLIT);
        int code = Integer.parseInt(strs[0]);
        switch (code) {
            case SocketEnum.CONN:
                conn_Receive(ctx, strs[1]);
                break;
            case SocketEnum.JOINROOM:
                joinRoom_Receive(ctx, strs[1]);
                break;
            case SocketEnum.BEGIN:
                begin_Receive(ctx, strs[1]);
                break;
            case SocketEnum.SELECT:
                select_Receive(ctx, strs[1]);
                break;
            default:
                break;
        }
    }

    private void conn_Receive(ChannelHandlerContext ctx, String str) {
        try {
            //报文解密
            Map<String, Object> data = DecryptUtil.getValidData(JsonUtils.string2Map(str.replaceAll(" ", "+")));
            //反序列化
            ConneReq req = JsonUtils.string2Object(JsonUtils.object2String(data), ConneReq.class);
            sendMessage(ctx, gameService.conn(ctx.channel(), req), SocketEnum.connI);
        } catch (ManagedException e) {
            TishiManager.sendTishi(ctx.channel(), e.getMessage());
            ctx.close();
        } catch (Exception e) {
            logger.error("初始化连接发生未知错误！", e);
            ctx.close();
        }
    }

    private void joinRoom_Receive(ChannelHandlerContext ctx, String body) {
        Long playerId = ctx.channel().attr(PLAYER_KEY).get();
        if (null == playerId) {
            logger.debug("关闭未验证的连接！");
            ctx.close();//未验证签名的连接
            return;
        }
        try {
            gameService.joinRoom(ctx, playerId, Integer.parseInt(body));
        } catch (ManagedException e) {
            logger.error("{}", e.getMessage());
            TishiManager.sendTishi(ctx.channel(), e.getMessage());
            ctx.close();
        } catch (Exception e) {
            logger.error("进入房间发生未知错误！", e);
            ctx.close();
        }
    }

    private void begin_Receive(ChannelHandlerContext ctx, String body) {
        Long playerId = ctx.channel().attr(PLAYER_KEY).get();
        if (null == playerId) {
            logger.debug("关闭未验证的连接！");
            ctx.close();//未验证签名的连接
            return;
        }
        try {
            gameService.begin_Receive(playerId, Integer.parseInt(body));
        } catch (NumberFormatException e) {
            logger.error("参数有误！", new Object[]{e});
        } catch (ManagedException e) {
            logger.error("{}", e.getMessage());
            TishiManager.sendTishi(ctx.channel(), e.getMessage());
        } catch (Exception e) {
            logger.error("获取游戏结果发生未知错误！", e);
        }
    }

    private void select_Receive(ChannelHandlerContext ctx, String body) {
        Long playerId = ctx.channel().attr(PLAYER_KEY).get();
        if (null == playerId) {
            ctx.close();//未验证签名的连接
            return;
        }
        try {
            gameService.select(playerId, Integer.parseInt(body));
        } catch (NumberFormatException e) {
            logger.error("参数有误！", new Object[]{e});
        } catch (ManagedException e) {
            logger.error("{}", e.getMessage());
            TishiManager.sendTishi(ctx.channel(), e.getMessage());
        } catch (Exception e) {
            logger.error("选择小游戏卡牌发生未知错误！", e);
        }
    }

    private void sendMessage(ChannelHandlerContext ctx, String message, int code) {
        ctx.writeAndFlush(Unpooled.copiedBuffer((code + NetServer.MSG_SPLIT + message + NetServer.MSG_END).getBytes()));
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) {
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        Long playerId = ctx.channel().attr(PLAYER_KEY).get();
        try {
            if (null != playerId) {
                gameService.exit(playerId);
                ctx.channel().attr(PLAYER_KEY).set(null);
            }
            if (ctx.channel().isActive()) {
                ctx.close();
            }
        } catch (Exception e) {
            logger.error("玩家[{}]退出游戏发生错误！", playerId, e);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        logger.error("{}\tError: {} - {}", new Object[]{cause.getClass().getName(), cause.getMessage(),
                ctx.channel().remoteAddress(),});
        // 出现异常时关闭channel
        ctx.close();
    }
}